#pragma once

#include "Types.h"
#include <vector>

namespace My {

class Range;
class RangeItem;

/**
 * Describes a set of visual elements stacked up together
 * which can be resized individually (e.g. rows or columns)
 */
class Range {
	friend class RangeItem;
public:
	Range();
public:
	/// Total size of the Range
	Size GetSize() const; 
	/// Position in "space"
	Span GetBounds() const;
	bool IsEmpty() const;
	Size GetItemCount() const;
	RangeItem & GetItem(Size) const;
	int ItemIndexAt(int) const;
	void Append(RangeItem * pItem)
		{ Insert(GetItemCount(), &pItem, 1); }
	void Insert(Size pos, RangeItem * pItem)
		{ Insert(pos, &pItem, 1); }
	void Insert(Size pos, RangeItem * items[], Size count);
	void Remove(Size pos, Size count = 1);
	void Clear();
protected:
	/// Positioning of the first item
	virtual int GetOffset() const = 0;
	virtual void InvalidateSpan(Span) = 0;
	virtual void SizeChanged() = 0;
	void InvalidateItems(Size from = 0);
	void UpdateItems();
	bool IsValid() const;
private:
	Span GetItemBounds(const RangeItem &) const;
	Size GetItemIndex(const RangeItem &) const;
private:
	std::vector<RangeItem *>	m_Items;
	Size						m_Size;
	bool						m_Invalid;
	Size						m_InvalidRow;
};

class RangeItem {
	friend class Range;
public:
	RangeItem();
	/// Creates fictitious item with given offset
	RangeItem(Size offset) :
		m_pRange(0), m_Size(0), m_Index(-1), m_Offset(offset) { }
public:
	/// Individual item size
	Size GetSize() const
		{ return m_Size; }
	/// Offset from the range start
	Size GetOffset() const
		{ return m_Offset; }
	/// Position in "space"
	Span GetBounds() const;
	/// If this item is not in a range, it returns -1
	int GetIndex() const;
protected:
	Range * GetRange() const
		{ return m_pRange; }
	void Resize(Size);
	virtual void BoundsChanged() { }
protected:
	Range *		m_pRange;
	Size		m_Size;
	Size		m_Index;
	Size		m_Offset;
};

} // My